//============================================================================================
/**
 * @file
 * @brief
 * @date	2006.05.23
 * @author	Nozomu Saito
 *
 */
//============================================================================================
#ifdef PM_DEBUG

#include "common.h"
#include "system/procsys.h"
#include "system/arc_util.h"
#include "system/wipe.h"
#include "system/palanm.h"
#include "application/app_tool.h"
#include "system/snd_tool.h"

typedef struct WAVE_DEMO_WORK_tag
{
	GF_CAMERA_PTR CameraPtr;//カメラ
	NNSG3dRenderObj			RenderObj;
	NNSG3dResMdl* Model;
	NNSG3dResFileHeader* ResFile;
//	void *AnmMem[ANIME_TYPE_NUM];
//	NNSFndAllocator AnimeAllocator;
//	NNSG3dAnmObj* AnmObj[ANIME_TYPE_NUM];
	VecFx32 Target;	//注視点
	u8 EndFlg;
}WAVE_DEMO_WORK;

typedef struct ARC_TBL_tag
{
	u16 nsbmd;
	u16 anime[4];
}ARC_TBL;

typedef struct STRIP_TBL_tag
{
	int x;
	int z;
}STRIP_TBL;


typedef struct WAVE_DATA_tag
{
	u16 Width;
	u16 Height;
	float PlaneA[31*31];
	float PlaneB[31*31];
}WAVE_DATA;

static void InitDisp( const int inHeapID );
static void TestDraw(void);
///static void LoadData(WAVE_DEMO_WORK *wk);
static void MakeStrip(const int inLine, const int inPolyNum,
		const int inXOfs, const int inZOfs, STRIP_TBL *outTbl);
static void WaveMain(void);

//カメラ設定
static const GF_CAMERA_PARAM CameraData = {
	/*0x29aec1*/0xF0000,
	{
		-0x29fe,0,0
	},
	GF_CAMERA_PERSPECTIV,
	0x05c1,
	0	//dummy
};
#if 0
//アーカイブインデックステーブル
static ARC_TBL ArcTbl[4] = {
	{
		NARC_ship_demo_c_demo_D_nsbmd,
		{
			NARC_ship_demo_c_demo_D_nsbca,
			NARC_ship_demo_c_demo_D_nsbma,
			NARC_ship_demo_c_demo_D_nsbta,
			NARC_ship_demo_c_demo_D_nsbtp
		}
	},
	{
		NARC_ship_demo_c_demo_L_nsbmd,
		{
			NARC_ship_demo_c_demo_L_nsbca,
			NARC_ship_demo_c_demo_L_nsbma,
			NARC_ship_demo_c_demo_L_nsbta,
			NARC_ship_demo_c_demo_L_nsbtp
		}
	},
	{
		NARC_ship_demo_c_demo_R_nsbmd,
		{
			NARC_ship_demo_c_demo_R_nsbca,
			NARC_ship_demo_c_demo_R_nsbma,
			NARC_ship_demo_c_demo_R_nsbta,
			NARC_ship_demo_c_demo_R_nsbtp
		}
	},
	{
		NARC_ship_demo_c_demo_U_nsbmd,
		{
			NARC_ship_demo_c_demo_U_nsbca,
			NARC_ship_demo_c_demo_U_nsbma,
			NARC_ship_demo_c_demo_U_nsbta,
			NARC_ship_demo_c_demo_U_nsbtp
		}
	}
};
#endif
#define PLANE_WIDTH	(30)
#define VTX_NUM ( (PLANE_WIDTH+1)*2 )
#define DIV_SIZE	(PLANE_WIDTH / 2)
#define COLOR_NUM	( (PLANE_WIDTH+1)*(PLANE_WIDTH+1) )

static int OneGrid = FX32_ONE/DIV_SIZE;
static const VecFx32 PlaneScale = {FX32_ONE <<6, 0, FX32_ONE <<6};
static STRIP_TBL TestTbl[VTX_NUM*PLANE_WIDTH];
static int ColorInfo[COLOR_NUM];

static WAVE_DATA	WaveData;

static VecFx32 Point = {0,0,0};


PROC_RESULT WaveDemoProc_Init( PROC * proc, int * seq );
PROC_RESULT WaveDemoProc_Main( PROC * proc, int * seq );
PROC_RESULT WaveDemoProc_End( PROC * proc, int * seq );

//--------------------------------------------------------------------------------------------
/**
 * プロセス関数：初期化
 *
 * @param	proc	プロセスデータ
 * @param	seq		シーケンス
 *
 * @return	処理状況
 */
//--------------------------------------------------------------------------------------------
PROC_RESULT WaveDemoProc_Init( PROC * proc, int * seq )
{
	u8 i;
	WAVE_DEMO_WORK *wk;

	int heap_id = HEAPID_WAVEDEMO;

	sys_CreateHeap( HEAPID_BASE_APP, heap_id, 0x20000 );

	wk = PROC_AllocWork( proc, sizeof(WAVE_DEMO_WORK), heap_id );
	memset( wk, 0, sizeof(WAVE_DEMO_WORK) );

	//進行方向を取得
	wk->EndFlg = FALSE;

	wk->CameraPtr = GFC_AllocCamera(heap_id);	//カメラ作成
	InitDisp(heap_id);

///	LoadData(wk);


	//頂点データ作成
	{
		int i;
		for(i=0;i<PLANE_WIDTH;i++){
			MakeStrip(i, PLANE_WIDTH,
				-((PLANE_WIDTH/2)*OneGrid),-((PLANE_WIDTH/2)*OneGrid),
				&TestTbl[i*VTX_NUM]);
		}
	}

	//頂点カラーセット
	{
		int i;
		for(i=0;i<COLOR_NUM;i++){
			ColorInfo[i] = 31;
		}
	}

	//波データの初期化
	{
		int i;
		WaveData.Height = 31;
		WaveData.Width = 31;
		for(i=0;i<WaveData.Height*WaveData.Width;i++){
			WaveData.PlaneA[i] = 0;
			WaveData.PlaneB[i] = 0;
		}
	}

	{
		VecFx32 target = {0,0,0};
		//カメラセット
		GFC_InitCameraTDA( &target,
			CameraData.Distance,	// 距離
			&CameraData.Angle,	//
			CameraData.PerspWay,	// 投射影の角度
			CameraData.View,
			FALSE,				//バインドしない
			wk->CameraPtr
			);

		GFC_AttachCamera(wk->CameraPtr);
	}
	for(i=0;i<1;i++){
		VecFx16		lightVec = {0, -FX16_ONE, 0};
		//ライトセット
		NNS_G3dGlbLightVector(i,
							lightVec.x,
							lightVec.y,
							lightVec.z);
		NNS_G3dGlbLightColor(i, GX_RGB(20,0,0));
	}
/**
	//グローバルステート書き換え
	NNS_G3dGlbMaterialColorDiffAmb(
				dat->LightDataPtr->Diff,
				dat->LightDataPtr->Amb,
				dat->LightDataPtr->IsSetVtxColor);

	NNS_G3dGlbMaterialColorSpecEmi(
				dat->LightDataPtr->Spec,
				dat->LightDataPtr->Emi,
				dat->LightDataPtr->IsShininess);
*/
	// ポリゴンアトリビュート
	NNS_G3dGlbPolygonAttr(
				GX_LIGHTMASK_0,
				GX_POLYGONMODE_MODULATE,        // modulation mode
                GX_CULL_BACK,  // cull back
                0,             // polygon ID(0 - 63)
                31,            // alpha(0 - 31)
                0              // OR of GXPolygonAttrMisc's value
				);

	APP_WipeStart( APP_WIPE_IN, heap_id );
	return PROC_RES_FINISH;
}

static int TestLife = 0;

//--------------------------------------------------------------------------------------------
/**
 * プロセス関数：メイン
 *
 * @param	proc	プロセスデータ
 * @param	seq		シーケンス
 *
 * @return	処理状況
 */
//--------------------------------------------------------------------------------------------
PROC_RESULT WaveDemoProc_Main( PROC * proc, int * seq )
{
	WAVE_DEMO_WORK * wk = PROC_GetWork( proc );
	MtxFx33 rotate_tmp = {FX32_ONE,0,0,0,FX32_ONE,0,0,0,FX32_ONE};
	VecFx32 scale = {FX32_ONE,FX32_ONE,FX32_ONE};
	VecFx32 trans = {0,0,0};

	if (sys.trg & PAD_BUTTON_A ){
		//真ん中に波紋を発生
		WaveData.PlaneA[31*31/2] = 4.0;
		//寿命設定
		TestLife = 120;
	}else if (sys.trg & PAD_BUTTON_B ){
		int i;
		for(i=0;i<31*31;i++){
			WaveData.PlaneA[i] = 0;
			WaveData.PlaneB[i] = 0;
		}
	}
/**
	if (TestLife != 0){
		TestLife--;
	}else if (TestLife == 0){
		//寿命がきました
		OS_Printf("寿命がきた\n");
		WaveData.PlaneA[31*31/2] = 0.0;
		WaveData.PlaneB[31*31/2] = 0.0;
	}
*/
	//波データを頂点カラーに変更
	{
		int i;
		for(i=0;i<31*31;i++){
			float col = WaveData.PlaneB[i];
			if (col>4.0){
				col = 4.0;
			}else if(col<0){
				col = 0;
			}
			ColorInfo[i] = 31.0 * (1.0-(col/4.0));
		}
	}

	OS_Printf("MID=%f:COL=%d\n",WaveData.PlaneB[31*31/2],ColorInfo[31*31/2]);

	GF_G3X_Reset();
	GFC_CameraLookAt();

	TestDraw();

	NNS_G3dGlbFlush();
/**
	simple_3DModelDraw(&wk->RenderObj,
			          &trans, &rotate_tmp, &scale);
*/
	GF_G3_RequestSwapBuffers(GX_SORTMODE_MANUAL,GX_BUFFERMODE_W);

	//伝播処理
	WaveMain();

	return PROC_RES_CONTINUE;

}

//--------------------------------------------------------------------------------------------
/**
 * プロセス関数：終了
 *
 * @param	proc	プロセスデータ
 * @param	seq		シーケンス
 *
 * @return	処理状況
 */
//--------------------------------------------------------------------------------------------
PROC_RESULT WaveDemoProc_End( PROC * proc, int * seq )
{
#if 0
	u8 i;
	SHIP_DEMO_WORK * wk = PROC_GetWork( proc );
	//アニメ解放
	for(i=0;i<ANIME_TYPE_NUM;i++){
		NNS_G3dFreeAnmObj(	&wk->AnimeAllocator, wk->AnmObj[i]);
		sys_FreeMemoryEz(wk->AnmMem[i]);
	}
	//モデリングデータ解放
	sys_FreeMemoryEz(wk->ResFile);
	//カメラ解放
	GFC_FreeCamera(wk->CameraPtr);
	//ワーク解放
	PROC_FreeWork( proc );
	//3Ｄ関連終了
	simple_3DBGExit();
	//ヒープ解放
	sys_DeleteHeap( HEAPID_SHIPDEMO );
#endif
	return PROC_RES_FINISH;
}

//===========================================================================
/**
 *
 * ＶＲＡＭバンク設定
 *
 */
//===========================================================================
static void SetVramBank(void)
{
	GF_BGL_DISPVRAM vramSetTable = {
		GX_VRAM_BG_128_C,				// メイン2DエンジンのBG
		GX_VRAM_BGEXTPLTT_NONE,			// メイン2DエンジンのBG拡張パレット
		GX_VRAM_SUB_BG_32_H,			// サブ2DエンジンのBG
		GX_VRAM_SUB_BGEXTPLTT_NONE,		// サブ2DエンジンのBG拡張パレット
		GX_VRAM_OBJ_16_F,				// メイン2DエンジンのOBJ
		GX_VRAM_OBJEXTPLTT_NONE,		// メイン2DエンジンのOBJ拡張パレット
		GX_VRAM_SUB_OBJ_16_I,			// サブ2DエンジンのOBJ
		GX_VRAM_SUB_OBJEXTPLTT_NONE,	// サブ2DエンジンのOBJ拡張パレット
		GX_VRAM_TEX_01_AB,				// テクスチャイメージスロット
		GX_VRAM_TEXPLTT_0123_E			// テクスチャパレットスロット
	};
	GF_Disp_SetBank( &vramSetTable );
}

//----------------------------------------------------------------------------
/**
 * 画面初期化
 *
 * @return	none
 *
 */
//-----------------------------------------------------------------------------
static void InitDisp( const int inHeapID )
{
	sys_VBlankFuncChange( NULL, NULL );	// VBlankセット
	sys_HBlankIntrStop();				// HBlank停止

	GF_Disp_GX_VisibleControlInit();
	GF_Disp_GXS_VisibleControlInit();
	GX_SetVisiblePlane( 0 );
	GXS_SetVisiblePlane( 0 );

	SetVramBank();				// VRAM設定
	simple_3DBGInit(inHeapID);
	GF_Disp_DispSelect();	//3Ｄ面設定（上にするか、下にするか）
}

static void TestDraw(void)
{
// 描画開始
	//
	// 描画設定
	//
	NNS_G3dGePushMtx();
	{
		int i;
		///VecFx32		scal = { FX32_ONE<<4, FX32_ONE,FX32_ONE<<4 };
		VecFx32 pos = {0,0,0};
#if 0
		// 座標変換
		NNS_G3dGeTranslateVec( &pos );			// 平行移動
		NNS_G3dGeScaleVec(&scal);								// 拡縮
#endif
		// 位置設定
		NNS_G3dGlbSetBaseTrans(&pos);
		// スケール設定
		NNS_G3dGlbSetBaseScale(&PlaneScale);
		NNS_G3dGlbFlush();		//　ジオメトリコマンドを転送


		// ポリゴンアトリビュート設定
		NNS_G3dGePolygonAttr(
				   GX_LIGHTMASK_0,			  // ライトを反映しない
				   GX_POLYGONMODE_MODULATE,	  // モジュレーションポリゴンモード
				   GX_CULL_BACK,             // カリング
				   //GX_CULL_NONE,             // カリング
				   0,                         // ポリゴンＩＤ ０
				   31,					  // アルファ値
				   GX_POLYGON_ATTR_MISC_NONE );

		//NNS_G3dGlbMaterialColorDiffAmb(GX_RGB(0,31,0), GX_RGB(0,0,0), FALSE);

////		NNS_G3dGeColor( GX_RGB( 31, 5, 0 ) );
		// 四角形を描画開始

#if 0
		NNS_G3dGeBegin( /*GX_BEGIN_QUADS*/GX_BEGIN_QUAD_STRIP );
		{
/**
			// 色を変えるよう
			static int count1 = 0;
			static int count2 = 100000;
			static int count3 = 200000;

			// 色
			//NNS_G3dGeColor( GX_RGB( count1 / 10000, count2 / 10000, count3 / 10000 ) );


			// 各色の要素を変動させる
			count1 = (count1 + 5) % 160000;
			count2 = (count2 + 3) % 160000;
			count3 = (count3 + 1) % 160000;
*/
#if 0
			// 頂点
			NNS_G3dGeVtx( -OneGrid,  FX32_ONE, -OneGrid );
			NNS_G3dGeVtx( -OneGrid,  FX32_ONE,  OneGrid );
			NNS_G3dGeVtx(  0,  FX32_ONE,  -OneGrid );
			NNS_G3dGeVtx(  0,  FX32_ONE,  OneGrid );
///			NNS_G3dGeNormal(0, 0, 1<<9);
			NNS_G3dGeVtx(  OneGrid,  FX32_ONE, -OneGrid );
			NNS_G3dGeVtx(  OneGrid,  FX32_ONE, OneGrid );
#endif
			{
				int i;
				for(i=0;i<VTX_NUM;i++){
					NNS_G3dGeVtx( TestTbl[i].x, FX32_ONE, TestTbl[i].z );
				}
			}
		}
		// 描画終了
		NNS_G3dGeEnd();
#endif
		for(i=0;i<PLANE_WIDTH;i++){
			int j;
			STRIP_TBL *tbl = &TestTbl[i*VTX_NUM];
			NNS_G3dGeBegin( GX_BEGIN_QUAD_STRIP );
			for(j=0;j<VTX_NUM;j++){
				int col_idx;
				//クワッドストリップ順にカラーを参照するための計算
				col_idx = ((j+1)%2)*(j/2) + (j%2)*(((j-1)/2)+(PLANE_WIDTH+1));
				//オフセット
				col_idx += (i*(PLANE_WIDTH+1));
				NNS_G3dGeColor( GX_RGB( 0, 0, ColorInfo[col_idx]) );
				NNS_G3dGeVtx( tbl[j].x, FX32_ONE, tbl[j].z );
			}
			NNS_G3dGeEnd();
		}
/**
		NNS_G3dGlbSetBaseTrans(&Point);

		NNS_G3dGeBegin( GX_BEGIN_QUAD_STRIP );
		NNS_G3dGeColor( GX_RGB( 31, 0, 0) );
		NNS_G3dGeVtx( -FX32_ONE, FX32_ONE*2, -FX32_ONE );
		NNS_G3dGeVtx( -FX32_ONE, FX32_ONE*2, FX32_ONE );
		NNS_G3dGeVtx( FX32_ONE, FX32_ONE*2, FX32_ONE );
		NNS_G3dGeVtx( FX32_ONE, FX32_ONE*2, -FX32_ONE );
		NNS_G3dGeEnd();
*/
	}
	NNS_G3dGePopMtx(1);
}
#if 0
static void LoadData(WAVE_DEMO_WORK *wk)
{
	u8 i;
	NNSG3dResTex *texture;
	void *pAnmRes;
	ARCHANDLE* handle;
	//アーカイブハンドルオープン
	handle = ArchiveDataHandleOpen( ARC_SHIP_DEMO, HEAPID_WAVEDEMO );

	//モデリングデータをロード
	wk->ResFile = ArchiveDataLoadAllocByHandle( handle, NARC_ship_demo_asd_s01_m_nsbmd, HEAPID_WAVEDEMO );
	simple_3DModelSetResFileAlready( &wk->RenderObj, &wk->Model, &wk->ResFile );
	texture = NNS_G3dGetTex(wk->ResFile);	// テクスチャリソース取得
/**
	//モデリングデータはグローバルステートを使用する
	NNS_G3dMdlUseGlbDiff(wk->Model);			// ディフューズ
	NNS_G3dMdlUseGlbAmb(wk->Model);				// アンビエント
	NNS_G3dMdlUseGlbSpec(wk->Model);			// スペキュラー
	NNS_G3dMdlUseGlbEmi(wk->Model);				// エミッション

	for(i=0;i<ANIME_TYPE_NUM;i++){
		//アニメーションをロード
		wk->AnmMem[i] = ArchiveDataLoadAllocByHandle( handle, ArcTbl[wk->Dir].anime[i], HEAPID_SHIPDEMO );
		pAnmRes = NNS_G3dGetAnmByIdx(wk->AnmMem[i], 0);
		// 必要量のメモリをアロケートする。
		wk->AnmObj[i] = NNS_G3dAllocAnmObj( &wk->AnimeAllocator, // 使用するアロケータを指定
				                             pAnmRes,    // アニメーションリソースを指定
						                     wk->Model);    // モデルリソースを指定

		//イニシャライズ
		NNS_G3dAnmObjInit(wk->AnmObj[i], // アニメーションオブジェクトへのポインタ
		                  pAnmRes, // アニメリソースへのポインタ
			              wk->Model,  // NNSG3dResMdlへのポインタ
				          texture );  // NNSG3dResTexへのポインタ
		//アニメバインド
		NNS_G3dRenderObjAddAnmObj( &wk->RenderObj, wk->AnmObj[i] );
	}
*/
	//ハンドルクローズ
	ArchiveDataHandleClose( handle );
}
#endif
static void MakeStrip(const int inLine, const int inPolyNum,
		const int inXOfs, const int inZOfs, STRIP_TBL *outTbl)
{
	int i;
	int vtx_num;
	int x, z, z_base;
	//作成しようとする四角ポリゴンの数+1ｘ2が頂点数
	vtx_num = (inPolyNum+1)*2;
	x = 0;
	z_base = inLine * OneGrid;
	for(i=0;i<vtx_num;i++){
		z = z_base;
		if (i%2){
			z += OneGrid;
		}
		x = OneGrid*(i/2);
		outTbl[i].x = x+inXOfs;
		outTbl[i].z = z+inZOfs;
		OS_Printf("vertex%x,%x\n",x,z);
	}
}

//3D初期化
//
//
//ディスプレイリスト作成
//
//
//描画
//
//
//力点のセット
//
//
//伝播処理
static void WaveMain(void)
{
	int i;
	int max;
	int idx1,idx2,idx3,idx4;
	int base_w,base_h;
	//すべての頂点に対して計算する
	max = WaveData.Height*WaveData.Width;
	for(i=0;i<max;i++){
		int w,h;
		//2次座標に変換
		base_w = i%WaveData.Width;
		base_h = i/WaveData.Width;

		//周囲4つのデータ取得
		//左
		if (base_w-1>=0){
			w = base_w-1;
		}
		h = base_h;
		idx1 = h*WaveData.Width+w;

		//右
		if (base_w+1<WaveData.Width){
			w = base_w+1;
		}
		h = base_h;
		idx2 = h*WaveData.Width+w;

		//上
		if (base_h-1>=0){
			h = base_h-1;
		}
		w = base_w;
		idx3 = h*WaveData.Width+w;
		//下
		if(base_h+1<WaveData.Height){
			h = base_h+1;
		}
		w = base_w;
		idx4 = h*WaveData.Width+w;

		GF_ASSERT( (0<=idx1)&&(idx1<WaveData.Height*WaveData.Width) );
		GF_ASSERT( (0<=idx2)&&(idx2<WaveData.Height*WaveData.Width) );
		GF_ASSERT( (0<=idx3)&&(idx3<WaveData.Height*WaveData.Width) );
		GF_ASSERT( (0<=idx4)&&(idx4<WaveData.Height*WaveData.Width) );

		WaveData.PlaneA[i] += ( (WaveData.PlaneB[idx1]+WaveData.PlaneB[idx2]+WaveData.PlaneB[idx3]+WaveData.PlaneB[idx4])/4 \
							  - WaveData.PlaneB[i] );
		WaveData.PlaneA[i] *= 0.99;
	}

	//収束命令
	if (TestLife != 0){
		TestLife--;
	}else if (TestLife == 0){
		//寿命がきました
		OS_Printf("寿命がきた\n");
		WaveData.PlaneA[31*31/2] = 0.0;
		WaveData.PlaneB[31*31/2] = 0.0;
	}

	for(i=0;i<max;i++){
		WaveData.PlaneB[i] += WaveData.PlaneA[i];
/**
		if (WaveData.PlaneB[i] > 4){
			WaveData.PlaneB[i] = 4;
		}else if (WaveData.PlaneB[i]<0){
			WaveData.PlaneB[i] = 0;
		}
*/
	}
	OS_Printf("A::%f\n",WaveData.PlaneA[31*31/2]);
}

#endif	//PM_DEBUG